package org.papervision3d.events
{
	import flash.events.Event;
	import flash.events.EventPhase;
	import flash.events.MouseEvent;
	
	import org.papervision3d.cameras.Camera3D;
	import org.papervision3d.core.proto.FindNearestCallback;
	import org.papervision3d.core.proto.SceneObject3D;
	import org.papervision3d.objects.DisplayObject3D;
	import org.papervision3d.core.geom.DrawTriangle;
	import org.papervision3d.core.proto.MouseEventCallback;
	import flash.net.getClassByAlias;
	import org.papervision3d.core.geom.Vertex3D;
	import org.papervision3d.core.Matrix3D;
	import flash.geom.Point;
	import org.papervision3d.core.Number3D;
	
	public class MouseEventManager
	{
		public static const instance : MouseEventManager = new MouseEventManager();
		
		
		function MouseEventManager() {
			if( instance != null ) throw new Error( "EventManager is singleton, instancied itself, use 'instance' static property " );
			
		}
		
		
		public function findNearest(scene : SceneObject3D , camera:Camera3D ) : void
		{
			var callback:FindNearestCallback = new FindNearestCallback(scene.container.mouseX, scene.container.mouseY );
			callback.init( scene, camera, scene.clip );
		}
		
		
		//__________________________________________________________________ PRIVATES
		
		
		public function dispatch( type : String, _dispatchers : Array, callback : MouseEventCallback = null ) :void {
			
			//trace( "************* dispatch *************");
			if( callback.match ) {
				var v : Vertex3D =  new Vertex3D( callback.coordAtPoint.x,callback.coordAtPoint.y, callback.coordAtPoint.z );
				var n : Number3D =  new Number3D( callback.normalAtPoint.x,callback.normalAtPoint.y, callback.normalAtPoint.z );
				var mapP : Point = callback.materialCoordinates; 
			}
			
			
			var len : uint = _dispatchers.length;
			var object : DisplayObject3D = _dispatchers[ len-1 ]; 
			var i : uint;
			
			var event : MouseEvent3D;
			var dispatcher : DisplayObject3D;
			
		
			// __________________________________________________________________________
			//																Capture phase
			
			// Pou l'instant je ne sais pas comment difuser en capture																Capture phase
			
			/* for( i = 0; i < (len - 1); i++ ) 
			{
				dispatcher = _dispatchers[i];
				event = new MouseEvent3D( type, fc.object, dispatcher, EventPhase.CAPTURING_PHASE, false );
				event.preventDefault();
				//event = new Event( e.type, false , false );
				dispatcher.dispatchEvent( event );
			} */
			
			
			// __________________________________________________________________________
			//																Target phase
			
			event = new MouseEvent3D( type, object, object, EventPhase.AT_TARGET, true, v, n, callback.face3d, mapP );
			event.preventDefault();
			
			object.dispatchEvent( event );
			//trace( object.name );
			
			// __________________________________________________________________________
			//																Bubbling phase
			i = _dispatchers.length - 1;
			
			while( --i > -1 )
			{
				if( event.stopped ) return;
				dispatcher = _dispatchers[i];
				if( v ) 
					localeToParentTransform( v, _dispatchers[i+1] );
				if( n )
					localeToParentTransform( n, _dispatchers[i+1] );
				event = new MouseEvent3D( type, object, dispatcher, EventPhase.BUBBLING_PHASE, true, v, n, callback.face3d, mapP );
				event.preventDefault();
				
				dispatcher.dispatchEvent( event );
				//trace( dispatcher.name );
			}
		}
		
		private function localeToParentTransform( v : *, parent : DisplayObject3D ) : void {
			var m:Matrix3D = parent.transform;
    		
    		//trace( "localeToParentTransform  : "+parent );
           
            var vx:Number = v.x;
            var vy:Number = v.y;
            var vz:Number = v.z;

            var sx:Number = vx * m.n11 + vy * m.n12 + vz * m.n13 + m.n14;
            var sy:Number = vx * m.n21 + vy * m.n22 + vz * m.n23 + m.n24;
            var sz:Number = vx * m.n31 + vy * m.n32 + vz * m.n33 + m.n34;

			v.x = sx;
			v.y = sy;
			v.z = sz;
    		//trace("  		", v.x, v.y, v.z );
		}
	}
}